var mongoose = require('mongoose'),
    BaseEnum = require('./Enum'),
    BaseFun = require('./Function'),
    Transaction = require('./Transaction'),
    referenceRelation = require('./ReferenceRelation');

var Entity = function(entityName, name, parentEntity){
    this._EntityName = entityName;                      //实体名称
    this._Entity = mongoose.model(this._EntityName);
    this._Name = name;                                  //实体中文名
    this._Childs = new Array();                        //子实体集合
    this._Parent = null;
    this._Fields = null;

    if(parentEntity != undefined && parentEntity != null){
        parentEntity.addChilds(this);
        this._Parent = parentEntity;
    }

    this.OnSetDefaultValue = null;
    this.OnValidate = null;
    this.OnInserting = null;
    this.OnInserted = null;
    this.OnUpdating = null;
    this.OnUpdated = null;
    this.OnDeleting = null;
    this.OnDeleted = null;
};

Entity.prototype = {
    get EntityName(){
        return this._EntityName;
    },
    get Name(){
        return this._Name;
    },
    get Entity(){
        return this._Entity;
    },
    get Parent(){
        return this._Parent;
    },
    get Fields(){
        return this._Fields;
    },
    get Childs(){
        return this._Childs;
    },

    addChilds: function(childEntity){
        this._Childs.push(childEntity);
    },

    save: function(records, resultHandel) {
        if(records.length > 1){
            Transaction.BatchSaveByTran([{EntityName: this.EntityName, Records: records}], resultHandel);
        }
        else {
            if (records[0].RowStatus == BaseEnum.RowStatus.Insert.Value) {
                if(records[0]._id != null && records[0]._id != undefined 
                    && records[0]._id.constructor === Number){
                    delete records[0]._id;
                }
                this.insert(records[0], resultHandel);
            }
            else if (records[0].RowStatus == BaseEnum.RowStatus.Modify.Value) {
                this.update(records[0], resultHandel);
            }
            else if (records[0].RowStatus == BaseEnum.RowStatus.Delete.Value) {
                this.delete(records[0], resultHandel);
            }
        }
    },
    delete: function(record, resultHandel){
        var self = this;

        this._validate(record).then(
            record => {return self._beforeDelete(record)}
        ).then(
            record => {return self._startDelete(record)}
        ).then(
            record => {return self._afterDelete(record)}
        ).then(
            record => resultHandel(null, record)
        ).catch(function(err){
            var newErr = new Error();
            newErr.message = err.message;
            if(err.hasOwnProperty('title')){
                newErr.title = '【' + self.Name + '】' + err.title;
            }
            else{
                newErr.title = '【' + self.Name + '】' + '删除失败';
            }
            if(err.hasOwnProperty('leval')){
                newErr.leval = err.leval;
            }
            else{
                newErr.leval = 5;
            }
            resultHandel(newErr);
        });
    },
    update: function(record, resultHandel){
        var self = this;
        var baseCheck = new Promise(function(resolve, reject) {
            self.findById(record._id, '', function(err, data){
                if(err){
                    err.leavl = 9;
                    err.title = '【' + self.Name + '】' + '查询错误';
                    reject(err);
                }
                else{
                    if(data == null){
                        var newErr = new Error();
                        newErr.leval = 1;
                        newErr.title = '【' + self.Name + '】' + '修改错误';
                        newErr.message = '修改数据不存在，可能被删除，请检查';
                        reject(newErr);
                    }
                    else if(data.SysVersion == undefined || data.SysVersion == null){
                        var newErr = new Error();
                        newErr.leval = 1;
                        newErr.title = '【' + self.Name + '】' + '修改错误';
                        newErr.message = '当前数据无版本信息，请检查';
                        reject(newErr);
                    }
                    else if(record.SysVersion != null && record.SysVersion != undefined && data.SysVersion != record.SysVersion){
                        var newErr = new Error();
                        newErr.leval = 9;
                        newErr.title = '【' + self.Name + '】' + '并发异常';
                        newErr.message = '当前数据已被他人修改';
                        reject(newErr);
                    }
                    else {
                        resolve(record);
                    }
                }
            })
        });

        baseCheck.then(
            record => {return self._setDefaultValue(record)}
        ).then(
            record => {return self._validate(record)}
        ).then(
            record => {return self._beforeUpdate(record)}
        ).then(
            record => {return self._startUpdate(record)}
        ).then(
            record => {return self._afterUpdate(record)}
        ).then(
            record => resultHandel(null, record)
        ).catch(function(err){
            var newErr = new Error();
            newErr.message = err.message;
            if(err.hasOwnProperty('title')){
                newErr.title = '【' + self.Name + '】' + err.title;
            }
            else{
                newErr.title = '【' + self.Name + '】' + '修改失败';
            }
            if(err.hasOwnProperty('leval')){
                newErr.leval = err.leval;
            }
            else{
                newErr.leval = 5;
            }
            resultHandel(newErr);
        });
    },
    insert: function(record, resultHandel){
        var self = this;

        this._setDefaultValue(record).then(
            record => {return self._validate(record)}
        ).then(
            record => {return self._beforeInsert(record)}
        ).then(
            record => {return self._startInsert(record)}
        ).then(
            record => {return self._afterInsert(record)}
        ).then(
            record => resultHandel(null, record)
        ).catch(function(err){
            var newErr = new Error();
            newErr.message = err.message;
            if(err.hasOwnProperty('title')){
                newErr.title = '【' + self.Name + '】' + err.title;
            }
            else{
                newErr.title = '【' + self.Name + '】' + '插入失败';
            }
            if(err.hasOwnProperty('leval')){
                newErr.leval = err.leval;
            }
            else{
                newErr.leval = 5;
            }
            resultHandel(newErr);
        });
    },
    deleteById: function(id, resultHandel){
        if(this.Childs.length > 0){
            for(var i=0; i<this.Childs.length; i++){
                this.Childs[i].deleteByCondition(eval("({" + this.EntityName + ": '" + id + "'})"), function(err){
                    if(err){
                        resultHandel(err);
                        return;
                    }
                });
            }
        }
        this.deleteByCondition({_id: id}, function(err, data){
            if(err){
                if(resultHandel != null && resultHandel != undefined) {
                    resultHandel(err);
                }
            }
            else{
                if(resultHandel != null && resultHandel != undefined) {
                    resultHandel(null, data);
                }
            }
        });
    },
    deleteByIds: function(ids, resultHandel){
        if(this.Childs.length > 0){
            for(var i=0; i<this.Childs.length; i++){
                this.Childs[i].deleteByCondition(eval("({" + this.EntityName + ": {$in: ids}})"), function(err){
                    if(err){
                        resultHandel(err);
                        return;
                    }
                });
            }
        }
        this.deleteByCondition({_id: {$in: ids}}, function(err, data){
            if(err){
                if(resultHandel != null && resultHandel != undefined) {
                    resultHandel(err);
                }
            }
            else{
                if(resultHandel != null && resultHandel != undefined) {
                    resultHandel(null, data);
                }
            }
        });
    },
    deleteByCondition: function(condition, resultHandel){
        var self = this;
        referenceRelation.deleteVerify(this.EntityName, condition, function(err){
            if(err){
                resultHandel(err);
            }
            else{
                self.Entity.remove(condition).exec(function(err, data){
                    if(err){
                        var newErr = new Error();
                        newErr.leval = 5;
                        newErr.title = '【' + self.Name + '】' + '删除错误';
                        newErr.message = err.message;
                        if(resultHandel != null && resultHandel != undefined) {
                            resultHandel(newErr);
                        }
                    }
                    else{
                        if(resultHandel != null && resultHandel != undefined) {
                            resultHandel(null, data);
                        }
                    }
                });
            }
        });
    },
    updateByValue: function(condition, value, resultHandel){
        var self = this;
        BaseFun.formatCondition(self, condition, function(err, newCondition){
            if(err){
                resultHandel(err);
            }
            else{
                self.Entity.update(newCondition, value, {multi: true}).exec(function(err, data){
                    if(err){
                        var newErr = new Error();
                        newErr.leval = 5;
                        newErr.title = '【' + self.Name + '】' + '修改错误';
                        newErr.message = err.message;
                        if(resultHandel != null && resultHandel != undefined) {
                            resultHandel(newErr);
                        }
                    }
                    else{
                        if(resultHandel != null && resultHandel != undefined) {
                            resultHandel(null, data);
                        }
                    }
                });
            }
        });
    },

    find: function(condition, orderBy, populate, resultHandel){
        if(populate == undefined || populate == null){
            populate = '';
        }
        var self = this;
        BaseFun.formatCondition(self, condition, function(err, newCondition){
            if(err){
                resultHandel(err);
            }
            else{
                self.Entity.find(newCondition).populate(populate).sort(orderBy).exec(function (err, data) {
                    if (err) {
                        var newErr = new Error();
                        newErr.leval = 5;
                        newErr.title = '【' + self.Name + '】' + '查找错误';
                        newErr.message = err.message;
                        resultHandel(newErr);
                    }
                    else {
                        resultHandel(null, data);
                    }
                });
            }
        });
    },
    findById: function(id, populate, resultHandel){
        if(populate == undefined || populate == null){
            populate = '';
        }
        var self = this;
        this.Entity.findById(id).populate(populate).exec(function(err, data){
            if(err){
                var newErr = new Error();
                newErr.leval = 5;
                newErr.title = '【' + self.Name + '】' + '查找错误';
                newErr.message = err.message;
                if(resultHandel != null && resultHandel != undefined) {
                    resultHandel(newErr);
                }
            }
            if(resultHandel != null && resultHandel != undefined) {
                resultHandel(null, data);
            }
        });
    },
    findOne: function(condition, populate, resultHandel){
        if(populate == undefined || populate == null){
            populate = '';
        }
        var self = this;
        BaseFun.formatCondition(self, condition, function(err, newCondition){
            if(err){
                resultHandel(err);
            }
            else{
                self.Entity.findOne(newCondition).populate(populate).exec(function(err, data){
                    if(err){
                        var newErr = new Error();
                        newErr.leval = 5;
                        newErr.title = '【' + self.Name + '】' + '查找错误';
                        newErr.message = err.message;
                        if(resultHandel != null && resultHandel != undefined) {
                            resultHandel(newErr);
                        }
                    }
                    else{
                        if(resultHandel != null && resultHandel != undefined) {
                            resultHandel(null, data);
                        }
                    }
                });
            }
        });
    },
    search: function(text, filter, limit, resultHandel){
        var self = this;
        this.Entity.db.db.command({text: this.EntityName, search: text, filter: filter, limit: limit }, function(err, data){
            if(err){
                var newErr = new Error();
                newErr.leval = 5;
                newErr.title = '【' + self.Name + '】' + '查找错误';
                newErr.message = err.message;
                if(resultHandel != null && resultHandel != undefined) {
                    resultHandel(newErr);
                }
            }
            else{
                var records = [];
                for(var i=0; i<data.results.length; i++) {
                    records.push(data.results[i].obj);
                }
                resultHandel(null, records);
            }
        });
    },

    distinct: function(field, condition, resultHandel){
        var self = this;
        BaseFun.formatCondition(this, condition, function(err, newCondition){
            if(err){
                resultHandel(err);
            }
            else{
                self.Entity.distinct(field, newCondition, function(err, data){
                    if(err){
                        var newErr = new Error();
                        newErr.leval = 5;
                        newErr.title = '【' + self.Name + '】' + '查询错误';
                        newErr.message = err.message;
                        if(resultHandel != null && resultHandel != undefined) {
                            resultHandel(newErr);
                        }
                    }
                    else{
                        resultHandel(null, data);
                    }
                });
            }
        });
    },
    //聚合函数
    mapReduce: function(option, condition, orderBy, resultHandel){
        var collectinName = "Tmp_" + BaseFun.getGuid();
        option.out = {replace: collectinName};
        option.verbose = true;
        this.Entity.mapReduce(option, function(err, model, stats){
            if(err){
                var newErr = new Error();
                newErr.leval = 5;
                newErr.title = '【' + self.Name + '】' + '查找错误';
                newErr.message = err.message;
                if(resultHandel != null && resultHandel != undefined) {
                    resultHandel(newErr);
                }
            }
            else{
                console.log('处理时间：', stats.processtime)
                model.find(condition).sort(orderBy).exec(function (err, data) {
                    mongoose.connection.db.dropCollection(collectinName);
                    if(err){
                        var newErr = new Error();
                        newErr.leval = 5;
                        newErr.title = '【' + self.Name + '】' + 'MapReduce完成后查找错误';
                        newErr.message = err.message;
                        if(resultHandel != null && resultHandel != undefined) {
                            resultHandel(newErr);
                        }
                    }
                    else{
                        resultHandel(null, data);
                    }
                });
            }
        });
    },
    aggregate: function(args, resultHandel){
        var self = this;
        BaseFun.formatCondition(self, args[0]['$match'], function(err, newCondition){
            if(err){
                resultHandel(err);
            }
            else{
                args[0]['$match'] = newCondition;
                self.Entity.aggregate(args).exec(function(err, data){
                    if(err){
                        var newErr = new Error();
                        newErr.leval = 5;
                        newErr.title = '【' + self.Name + '】' + '查找错误';
                        newErr.message = err.message;
                        if(resultHandel != null && resultHandel != undefined) {
                            resultHandel(newErr);
                        }
                    }
                    else{
                        resultHandel(null, data);
                    }
                });
            }
        });
    },
    aggregateSum: function(groupFieldName, valueFieldName, condition, resultHandel){
        var self = this;
        this.aggregate([
            {$match: condition},
            {$group : {_id : '$' + groupFieldName, value : {$sum: '$' + valueFieldName}}},
            {$sort: {value: 1}}
        ], function(err, data){
            if(err){
                var newErr = new Error();
                newErr.leval = 5;
                newErr.title = '【' + self.Name + '】' + '查找错误';
                newErr.message = err.message;
                if(resultHandel != null && resultHandel != undefined) {
                    resultHandel(newErr);
                }
            }
            else{
                resultHandel(null, data);
            }
        });
    },
    aggregateCount: function(groupFieldName, condition, resultHandel){
        var self = this;
        this.aggregate([
            {$match: condition},
            {$group : {_id : '$' + groupFieldName, value : {$sum: 1}}},
            {$sort: {value: 1}}
        ], function(err, data){
            if(err){
                var newErr = new Error();
                newErr.leval = 5;
                newErr.title = '【' + self.Name + '】' + '查找错误';
                newErr.message = err.message;
                if(resultHandel != null && resultHandel != undefined) {
                    resultHandel(newErr);
                }
            }
            else{
                resultHandel(null, data);
            }
        });
    },
    aggregateAvg: function(groupFieldName, valueFieldName, condition, resultHandel){
        var self = this;
        this.aggregate([
            {$match: condition},
            {$group : {_id : '$' + groupFieldName, value : {$avg: '$' + valueFieldName}}},
            {$sort: {value: 1}}
        ], function(err, data){
            if(err){
                var newErr = new Error();
                newErr.leval = 5;
                newErr.title = '【' + self.Name + '】' + '查找错误';
                newErr.message = err.message;
                if(resultHandel != null && resultHandel != undefined) {
                    resultHandel(newErr);
                }
            }
            else{
                resultHandel(null, data);
            }
        });
    },
    aggregateMax: function(groupFieldName, valueFieldName, condition, resultHandel){
        var self = this;
        this.aggregate([
            {$match: condition},
            {$group : {_id : '$' + groupFieldName, value : {$max: '$' + valueFieldName}}},
            {$sort: {value: 1}}
        ], function(err, data){
            if(err){
                var newErr = new Error();
                newErr.leval = 5;
                newErr.title = '【' + self.Name + '】' + '查找错误';
                newErr.message = err.message;
                if(resultHandel != null && resultHandel != undefined) {
                    resultHandel(newErr);
                }
            }
            else{
                resultHandel(null, data);
            }
        });
    },
    aggregateMin: function(groupFieldName, valueFieldName, condition, resultHandel){
        var self = this;
        this.aggregate([
            {$match: condition},
            {$group : {_id : '$' + groupFieldName, value : {$min: '$' + valueFieldName}}},
            {$sort: {value: 1}}
        ], function(err, data){
            if(err){
                var newErr = new Error();
                newErr.leval = 5;
                newErr.title = '【' + self.Name + '】' + '查找错误';
                newErr.message = err.message;
                if(resultHandel != null && resultHandel != undefined) {
                    resultHandel(newErr);
                }
            }
            else{
                resultHandel(null, data);
            }
        });
    },

    pageQuery: function(condition, orderBy, populate, pageNum, pageSize, resultHandel) {
        if(populate == undefined || populate == null){
            populate = '';
        }
        var self = this;
        BaseFun.formatCondition(self, condition, function(err, newCondition){
            if(err){
                resultHandel(err);
            }
            else{
                self.Entity.find(newCondition)
                    .populate(populate).sort(orderBy)
                    .skip(pageNum * pageSize)
                    .limit(pageSize)
                    .exec(function(err, data){
                    if(err){
                        var newErr = new Error();
                        newErr.leval = 5;
                        newErr.title = '【' + self.Name + '】' + '查找错误';
                        newErr.message = err.message;
                        if(resultHandel != null && resultHandel != undefined) {
                            resultHandel(newErr);
                        }
                    }
                    else{
                        resultHandel(null, data);
                    }
                });
            }
        });
    },
    queryRecordCount: function(condition, resultHandel){
        var self = this;
        BaseFun.formatCondition(self, condition, function(err, newCondition){
            if(err){
                resultHandel(err);
            }
            else{
                self.Entity.find(newCondition).count().exec(function(err, data){
                    if(err){
                        var newErr = new Error();
                        newErr.leval = 5;
                        newErr.title = '【' + self.Name + '】' + '查找错误';
                        newErr.message = err.message;
                        if(resultHandel != null && resultHandel != undefined) {
                            resultHandel(newErr);
                        }
                    }
                    else{
                        resultHandel(null, data);
                    }
                });
            }
        });
    },
    findRecordIndex: function(id, condition, orderBy, resultHandel){
        var self = this;
        BaseFun.formatCondition(self, condition, function(err, newCondition){
            if(err){
                resultHandel(err);
            }
            else{
                self.Entity.find(newCondition, {'_id' : 1}).sort(orderBy)
                    .exec(function(err, records){
                    if(err){
                        var newErr = new Error();
                        newErr.leval = 5;
                        newErr.title = '【' + self.Name + '】' + '查找错误';
                        newErr.message = err.message;
                        if(resultHandel != null && resultHandel != undefined) {
                            resultHandel(newErr);
                        }
                    }
                    else{
                        var returnData = {
                            Index: -1,
                            Count: records.length
                        }
                        for(var i=0; i<records.length; i++){
                            if(records[i]._id == id){
                                returnData.Index = i;
                                break;
                            }
                        }
                        if(resultHandel != null && resultHandel != undefined) {
                            resultHandel(null, returnData);
                            // resultHandel(null, {
                            //     Length: data.length,
                            //     Index: data.toString().replace(/ /g,'').split(',').indexOf('{_id:' + id + '}')
                            // });
                        }
                    }
                });
            }
        });
    },

    _setDefaultValue: function(record){
        var self = this;
        var promise = new Promise(function(resolve, reject) {
            if(self.OnSetDefaultValue){
                if(self.OnSetDefaultValue.length == 0){
                    self.OnSetDefaultValue.apply(record);
                    resolve(record);
                }
                else{
                    self.OnSetDefaultValue.call(record, function(err){
                        if(err){
                            reject(err);
                        }
                        else{
                            resolve(record);
                        }
                    });
                }
            }
            else{
                resolve(record);
            }
        });
        return promise;
    },
    _validate: function(record){
        var self = this;
        var promise = new Promise(function(resolve, reject) {
            if(self.OnValidate){
                if(self.OnValidate.length == 0){
                    self.OnValidate.apply(record);
                    resolve(record);
                }
                else{
                    self.OnValidate.call(record, function(err){
                        if(err){
                            reject(err);
                        }
                        else{
                            resolve(record);
                        }
                    });
                }
            }
            else{
                resolve(record);
            }
        });
        return promise;
    },
    _beforeDelete: function(record){
        var self = this;
        var promise = new Promise(function(resolve, reject) {
            if(self.OnDeleting){
                if(self.OnDeleting.length == 0){
                    self.OnDeleting.apply(record);
                    resolve(record);
                }
                else{
                    self.OnDeleting.call(record, function(err){
                        if(err){
                            reject(err);
                        }
                        else{
                            resolve(record);
                        }
                    });
                }
            }
            else{
                resolve(record);
            }
        });
        return promise;
    },
    _startDelete: function(record){
        var self = this;

        var promise = new Promise(function(resolve, reject) {
            self.deleteById(record._id, function(err, data){
                if(err){
                    reject(err);
                }
                else{
                    resolve(record);
                }
            });
        });
        return promise;
    },
    _afterDelete: function(record){
        var self = this;
        var promise = new Promise(function(resolve, reject) {
            if(self.OnDeleted){
                if(self.OnDeleted.length == 0){
                    self.OnDeleted.apply(record);
                    resolve(record);
                }
                else{
                    self.OnDeleted.call(record, function(err){
                        if(err){                                        
                            reject(err);
                        }
                        else{
                            resolve(record);
                        }
                    });
                }
            }
            else{ 
                resolve(record);
            }
        });
        return promise;
    },
    _beforeUpdate: function(record){
        var self = this;
        var promise = new Promise(function(resolve, reject) {
            if(self.OnUpdating){
                if(self.OnUpdating.length == 0){
                    self.OnUpdating.apply(record);
                    resolve(record);
                }
                else{
                    self.OnUpdating.call(record, function(err){
                        if(err){
                            reject(err);
                        }
                        else{
                            resolve(record);
                        }
                    });
                }
            }
            else{
                resolve(record);
            }
        });
        return promise;
    },
    _startUpdate: function(record){
        var self = this;
        
        delete record.RowStatus;
        record.SysVersion = record.SysVersion + 1;
        record.ModifyOn = new Date();
        var promise = new Promise(function(resolve, reject) {
            self.Entity.update({_id: record._id}, {$set: record})
                .exec(function(err, count) {
                    if (err) {
                        err.leavl = 9;
                        err.title = '【' + self.Name + '】' + '修改错误';
                        reject(err);
                    } else {
                        self.Entity.findById(record._id, function(err, entity) {
                            if (err) {
                                err.leavl = 9;
                                err.title = '【' + self.Name + '】' + '查询错误';
                                err.message = '保存完成后，查找数据出错，' + err.message;
                                reject(err);
                            } else {
                                resolve(entity);
                            }
                        });
                    }
                }
            );
        });
        return promise;
    },
    _afterUpdate: function(record){
        var self = this;
        var promise = new Promise(function(resolve, reject) {
            if(self.OnUpdated){
                if(self.OnUpdated.length == 0){
                    self.OnUpdated.apply(record);
                    resolve(record);
                }
                else{
                    self.OnUpdated.call(record, function(err){
                        if(err){                                        
                            reject(err);
                        }
                        else{
                            resolve(record);
                        }
                    });
                }
            }
            else{ 
                resolve(record);
            }
        });
        return promise;
    },
    _beforeInsert: function(record){
        var self = this;
        var promise = new Promise(function(resolve, reject) {
            if(self.OnInserting){
                if(self.OnInserting.length == 0){
                    self.OnInserting.apply(record);
                    resolve(record);
                }
                else{
                    self.OnInserting.call(record, function(err){
                        if(err){
                            reject(err);
                        }
                        else{
                            resolve(record);
                        }
                    });
                }
            }
            else{
                resolve(record);
            }
        });
        return promise;
    },
    _startInsert: function(record){
        delete record.RowStatus;
        record.CreatedOn = new Date();
        record.SysVersion = 0;

        var self = this;
        var promise = new Promise(function(resolve, reject) {
            var newEntity = new self.Entity(record);
            newEntity.save(function(err, data){
                if(err){
                    var newErr = new Error();
                    newErr.leval = 9;
                    newErr.title = '【' + self.Name + '】' + '新增错误';
                    newErr.message = err.message;
                    reject(newErr);
                }
                else{   
                    resolve(data);
                }
            });
        });
        return promise;
    },
    _afterInsert: function(record){
        var self = this;
        var promise = new Promise(function(resolve, reject) {
            if(self.OnInserted){
                if(self.OnInserted.length == 0){
                    self.OnInserted.apply(record);
                    resolve(record);
                }
                else{
                    self.OnInserted.call(record, function(err){
                        if(err){                                        
                            reject(err);
                        }
                        else{
                            resolve(record);
                        }
                    });
                }
            }
            else{ 
                resolve(record);
            }
        });
        return promise;
    }
};

module.exports = Entity;
